/* Includes ------------------------------------------------------------------*/
#include "Global_types.h"
#include "GPIO.hpp"

/* Static members definition -------------------------------------------------*/
u8 TGPIO_manager::Ref = 0;

GPIO_ACCESS_type TGPIO_manager::Gpio[] = 
{
  {GPIOA, RCC_AHBENR_GPIOAEN, 0},
  {GPIOB, RCC_AHBENR_GPIOBEN, 0},
  {GPIOC, RCC_AHBENR_GPIOCEN, 0},
  {GPIOD, RCC_AHBENR_GPIODEN, 0},
  {GPIOF, RCC_AHBENR_GPIOFEN, 0},
};

/** ----------------------------------------------------------------------------
* @brief  GPIO_manager - Class constructor
* @param  
* @retval 
*/
TGPIO_manager::TGPIO_manager()
{ 
  if(Ref != 0) 
  {
    /* Object creation failed */
    while(1);
  }
  else Ref = 0xFF;
}

/** ----------------------------------------------------------------------------
* @brief  Init
* @param  
* @retval 
*/
u32 TGPIO_manager::Init(GPIO_NUM_type N, u16 PinMsk, GPIO_MODE_type Mode, GPIO_OUT_type Out)
{
  /* Checking access */
  if((N >= GPIO_Numbers_ALL) || (Gpio[N].AccessMsk & PinMsk))
  {
     /* Error fixing */
     GPIO_LOG(GPIO_ERR_GPIO_ACCESS_DENIED);
     return 1;
  }
  
  /* Lock current pins */
  Gpio[N].AccessMsk |= PinMsk;
  
  /* Enable clock */
  RCC->AHBENR |=  Gpio[N].RccMsk;
  
  /* Set settings to registers */
  for(u16 PinNum=0; PinNum<16; PinNum++)
  {
    if((PinMsk >> PinNum) & 0x1)
    {
      Gpio[N].Reg->OSPEEDR |= (GPIO_Speed_50MHz << (2*PinNum));
      Gpio[N].Reg->MODER   |= ((Mode & 0x3)     << (2*PinNum));
      Gpio[N].Reg->OTYPER  |= ((Out & 0x3)      << PinNum);
      Gpio[N].Reg->PUPDR   |= ((Out >> 2)       << (2*PinNum));
      if(PinNum<8) 
      Gpio[N].Reg->AFR[0]  |= ((Mode >> 2)      << (4*PinNum));
      else
      Gpio[N].Reg->AFR[1]  |= ((Mode >> 2)      << (4*(PinNum-8)));
      
      if((Gpio[N].Reg->OSPEEDR & (GPIO_Speed_50MHz << (2*PinNum))) == 0)
      {
         /* Error fixing */
         GPIO_LOG(GPIO_ERR_PIN_IS_NOT_AVAILABLE);
         return 1;
      }
    }
  }
  
  return 0;
}

/** ----------------------------------------------------------------------------
* @brief  GPIO_Free
* @param  
* @retval 
*/
u32 TGPIO_manager::DeInit(GPIO_NUM_type Num, u16 PinMsk)
{  
  /* Checking access */
  if(Num >= GPIO_Numbers_ALL) 
  {
     /* Error fixing */
     GPIO_LOG(GPIO_ERR_GPIO_ACCESS_DENIED);
     return 1;
  }
  
  /* Allow access */
  Gpio[Num].AccessMsk &= ~PinMsk;  
  
  return 0;
}

/* End of file ---------------------------------------------------------------*/
